using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input.Touch;

namespace GameFramework
{
    /// <summary>
    /// This class is responsible of reading the game inputs.
    /// </summary>
    public class GameInput
    {        
        /// <summary>
        /// The accelerometer.
        /// </summary>
        private static Accelerometer accelerometer;

        /// <summary>
        /// True if the accelerometer is started.
        /// </summary>
        private static bool isAccelerometerStarted;

        /// <summary>
        /// Initializes a new instance of the <see cref="GameInput"/> class.
        /// </summary>
        public GameInput()
        {
            // By default we are not interested in any gestures
            TouchGestures = new List<GestureSample>();
            EnabledGestures = GestureType.None;

            // By default the accelerometer is disactvated
            isAccelerometerStarted = false;

            if (accelerometer == null)
            {
                // Setup the accelerometer
                accelerometer = new Accelerometer();
                accelerometer.ReadingChanged += OnAccelerometerReadingChanged;
            }
        }

        /// <summary>
        /// Gets the current touch collection.
        /// </summary>
        public TouchCollection TouchCollection { get; private set; }

        /// <summary>
        /// Gets the current touch gestures.
        /// </summary>
        public List<GestureSample> TouchGestures { get; private set; }

        /// <summary>
        /// Gets the accelerometer data.
        /// Use this property to get information about the accelerometer.
        /// </summary>
        public Vector3 AccelerometerData { get; private set; }

        /// <summary>
        /// Gets or sets the gesture that are enabled for the touch panel.
        /// </summary>
        public GestureType EnabledGestures
        {
            get { return TouchPanel.EnabledGestures; }
            set { TouchPanel.EnabledGestures = value; }
        }

        /// <summary>
        /// Read all the required inputs.
        /// </summary>
        public void Update()
        {
            TouchCollection = TouchPanel.GetState();

            TouchGestures.Clear();
            while (TouchPanel.IsGestureAvailable)
            {
                TouchGestures.Add(TouchPanel.ReadGesture());
            }
        }

        /// <summary>
        /// Start the accelerometer.
        /// </summary>
        public void StartAccelerometer()
        {
            if (isAccelerometerStarted)
            {
                return;
            }

            try
            {
                accelerometer.Start();
                isAccelerometerStarted = true;
            }
            catch (AccelerometerFailedException e)
            {
                isAccelerometerStarted = false;
                
                Debug.WriteLine(e.Message);
            }
        }

        /// <summary>
        /// Stop the accelerometer.
        /// </summary>
        public void StopAccelerometer()
        {
            if (!isAccelerometerStarted)
            {
                return;
            }

            try
            {
                accelerometer.Stop();
                isAccelerometerStarted = false;
            }
            catch (UnauthorizedAccessException ex)
            {
                Debug.WriteLine(ex.Message);                    
            }
            catch (AccelerometerFailedException ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// Dispose the accelerometer.
        /// </summary>
        public void DisposeAccelerometer()
        {
            // This method internally stop the accelerometer and it handles all the exceptions.
            accelerometer.Dispose();
        }

        /// <summary>
        /// Event handler of the accelerometer.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">Information on the accelerometer.</param>
        private void OnAccelerometerReadingChanged(object sender, AccelerometerReadingEventArgs e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(
                () => AccelerometerData = new Vector3((float)e.X, (float)e.Y, (float)e.Z));
        }
    }
}
